package com.crb.oauth2.api;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.crb.oauth2.api.alipay.AlipayConfig;
import com.crb.oauth2.api.dingding.DingDingConfig;
import com.crb.oauth2.api.dingding.DingDingTools;
import com.crb.oauth2.api.wechat.cp.config.WxCpConfiguration;
import com.crb.oauth2.api.wechat.cp.controller.BaseController;
import com.crb.oauth2.api.wechat.cp.enums.Oauth2Channel;
import com.crb.oauth2.api.wechat.cp.utils.JsonUtils;
import com.crb.oauth2.api.wechat.cp.utils.UrlUtils;
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
import com.dingtalk.api.response.OapiUserGetResponse;
import com.google.common.collect.Maps;
import com.taobao.api.ApiException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;


/**
 * 扫码登录SDK接口
 * OAuth2.0
 *
 * @author huangjian
 */
@AllArgsConstructor
@Slf4j
@Controller
@RequestMapping("/sdk/oauth_qr")
public class QrOauthSdkController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private DingDingTools dingDingTools;
    @Autowired
    private DingDingConfig dingDingConfig;
    @Autowired
    private AlipayConfig alipayConfig;
    @Autowired
    private WxMpService wxMpService;

    @RequestMapping("/oauth2")
    public String oauth2(@RequestParam("agentId") String agentId,
                         @RequestParam("channelCode") String channelCode,
                         @RequestParam("srcUrl") String srcUrl,
                         ModelMap map,
                         HttpServletResponse response) throws IOException {
        Oauth2Channel oauth2Channel = Oauth2Channel.valueOf(channelCode);
        String url = super.getServerDomain() + "/sdk/oauth_qr/greetDingDingUser";
        String redirectUri = "";
        try {
            redirectUri = URLEncoder.encode(url, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            logger.error("encode error: " + e.getMessage());
        }
        if (oauth2Channel == Oauth2Channel.CP_WECHAT) {
            url = super.getServerDomain() + "/sdk/oauth_qr/greetCpWxUser/" + agentId;
            redirectUri = "";
            try {
                redirectUri = URLEncoder.encode(url, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                logger.error("encode error: " + e.getMessage());
            }
            WxCpService cpService = WxCpConfiguration.getCpService(Integer.parseInt(agentId));
            map.put("appid", cpService.getWxCpConfigStorage().getCorpId());
            map.put("redirect_uri", redirectUri);
            map.put("agentid", agentId);
            map.put("state", srcUrl);
            return "sdk/wx_oauth2_qr";
        } else if (oauth2Channel == Oauth2Channel.MP_WECHAT) {
            url = super.getServerDomain() + "/sdk/oauth_qr/greetMpWxUser/" + agentId;
            redirectUri = "";
            try {
                redirectUri = URLEncoder.encode(url, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                logger.error("encode error: " + e.getMessage());
            }
            String qrConnectUrl = wxMpService.switchoverTo(agentId)
                    .buildQrConnectUrl(redirectUri, WxConsts.OAuth2Scope.SNSAPI_USERINFO, srcUrl);
            System.out.println("qrConnectUrl:" + qrConnectUrl);
            response.sendRedirect(qrConnectUrl);
        } else if (oauth2Channel == Oauth2Channel.DINGDING_QR01) {
            DingDingConfig.Oauth2 oauth2 = dingDingConfig.getOauth2();
            String redirect_uri = String.format(oauth2.getDingding_qr_oauth2(), oauth2.getAppkey(), srcUrl, url);
            response.sendRedirect(redirect_uri);
        } else if (oauth2Channel == Oauth2Channel.DINGDING_QR02) {
            DingDingConfig.Oauth2 oauth2 = dingDingConfig.getOauth2();
            String redirect_uri = String.format(oauth2.getDingding_oauth2(), oauth2.getAppkey(), srcUrl, redirectUri);
            map.put("redirect_uri", redirect_uri);
            return "sdk/ding_oauth2_qr";
        } else if (oauth2Channel == Oauth2Channel.DINGDING_H5) {
            DingDingConfig.Oauth2 oauth2 = dingDingConfig.getOauth2();
            String redirect_uri = String.format(oauth2.getDingding_oauth2(), oauth2.getAppkey(), srcUrl, redirectUri);
            System.out.println(redirect_uri);
            response.sendRedirect(redirect_uri);
        } else if (oauth2Channel == Oauth2Channel.ALIPAY) {
            String appId = alipayConfig.getAppId();
            if (!StringUtils.equals(appId, agentId)) {
                throw new IllegalArgumentException("appId参数错误，请检查");
            }
            String authGateway = alipayConfig.getAuthGateway();
            url = super.getServerDomain() + "/sdk/oauth_qr/greetAlipayUser/" + agentId.concat("/").concat(srcUrl);
            redirectUri = "";
            try {
                redirectUri = URLEncoder.encode(url, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                logger.error("encode error: " + e.getMessage());
            }
            String redirect_uri = String.format(authGateway, agentId, redirectUri);
            response.sendRedirect(redirect_uri);
        } else {
            throw new IllegalArgumentException("渠道" + channelCode + "错误");
        }
        return "error";
    }

    /**
     * @param code
     * @return
     * @throws ApiException
     */
    @RequestMapping("/greetDingDingUser")
    public void greetDingDingUser(@RequestParam String code,
                                  @RequestParam String state,
                                  HttpServletResponse response) throws Exception {
        OapiSnsGetuserinfoBycodeResponse userInfo = dingDingTools.getUserInfo(code);
        String unionid = userInfo.getUserInfo().getUnionid();
        OapiUserGetResponse userByUnionid = dingDingTools.getUserByUnionid(unionid);
        String srcUrl = new String(Base64Utils.decodeFromString(state));
        logger.info("srcUrl:{}", srcUrl);
        log.info("dingUser:{}", JsonUtils.toJson(userByUnionid));
        Map<String, String> map = Maps.newConcurrentMap();
        map.put("openId", userByUnionid.getOpenId());
        map.put("avatar", userByUnionid.getAvatar());
        map.put("nickName", URLEncoder.encode(userByUnionid.getName(), "UTF-8"));
        response.sendRedirect(UrlUtils.appendParams(srcUrl, map));
    }

    @RequestMapping("/greetCpWxUser/{agentId}/")
    public void greetCpWxUser(@PathVariable String agentId,
                              @RequestParam String code,
                              @PathVariable(name = "") String state,
                              HttpServletResponse response) {
        Integer agentIdInteger = Integer.parseInt(agentId);
        WxCpService cpService = WxCpConfiguration.getCpService(agentIdInteger);
        if (cpService == null) {
            throw new IllegalArgumentException(String.format("未找到对应agentId=[%s]的配置，请核实！", agentId));
        }
        try {
            WxCpOAuth2Service oauth2Service = cpService.getOauth2Service();
            WxCpOauth2UserInfo userInfo = oauth2Service.getUserInfo(code);
            String openId = userInfo.getOpenId();
            String userId = userInfo.getUserId();
            WxCpUserService userService = cpService.getUserService();
            //兼容企业微信和微信两种认证方式
            if (!StringUtils.isNotEmpty(userId)) {
                userId = userService.openid2UserId(openId);
            }
            if (StringUtils.isNotEmpty(userId)) {
                Map<String, String> openId1 = userService.userId2Openid(userId, agentIdInteger);
                openId = openId1.get("openid");
            }
            logger.info("code:{},state:{},openId:{}", code, state, openId);
            WxCpUser user = userService.getById(userId);
            String srcUrl = new String(Base64Utils.decodeFromString(state));
            logger.info("srcUrl:{}", srcUrl);
            log.info("WxCpUser:{}", JsonUtils.toJson(user));
            Map<String, String> map = Maps.newConcurrentMap();
            map.put("openId", openId);
            map.put("avatar", user.getAvatar());
            map.put("nickName", URLEncoder.encode(user.getName(), "UTF-8"));
            response.sendRedirect(UrlUtils.appendParams(srcUrl, map));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @RequestMapping("/greetMpWxUser/{agentId}")
    public void greetMpWxUser(@PathVariable String agentId,
                              @RequestParam String code,
                              @RequestParam String state,
                              HttpServletResponse response) {
        WxMpService mpService = this.wxMpService.switchoverTo(agentId);
        if (mpService == null) {
            throw new IllegalArgumentException(String.format("未找到对应agentId=[%s]的配置，请核实！", agentId));
        }
        try {
            WxMpOAuth2AccessToken accessToken = mpService.getOAuth2Service().getAccessToken(code);
            WxMpUser user = mpService.getOAuth2Service().getUserInfo(accessToken, null);
            logger.info("code:{},state:{},openId:{}", code, state, user.getOpenId());
            String srcUrl = new String(Base64Utils.decodeFromString(state));
            logger.info("srcUrl:{}", srcUrl);
            log.info("WxCpUser:{}", JsonUtils.toJson(user));
            Map<String, String> map = Maps.newConcurrentMap();
            map.put("openId", user.getOpenId());
            map.put("avatar", user.getHeadImgUrl());
            map.put("nickName", URLEncoder.encode(user.getNickname(), "UTF-8"));
            response.sendRedirect(UrlUtils.appendParams(srcUrl, map));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @RequestMapping("/greetAlipayUser/{agentId}/{srcUrl}")
    public void greetAlipayUser(@PathVariable String agentId,
                                @RequestParam String auth_code,
                                @PathVariable String srcUrl,
                                HttpServletResponse response) {
        String appId = alipayConfig.getAppId();
        if (!StringUtils.equals(appId, agentId)) {
            throw new IllegalArgumentException(String.format("未找到对应agentId=[%s]的配置，请核实！", agentId));
        }
        try {
            // 获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getGatewayUrl(), agentId,
                    alipayConfig.getMerchantPrivateKey(), alipayConfig.getDataType(), alipayConfig.getCharset(),
                    alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());
            // 获取用户信息授权
            AlipaySystemOauthTokenRequest alipaySystemOauthTokenRequest = new AlipaySystemOauthTokenRequest();
            alipaySystemOauthTokenRequest.setCode(auth_code);
            alipaySystemOauthTokenRequest.setGrantType("authorization_code");
            AlipaySystemOauthTokenResponse alipaySystemOauthTokenResponse = alipayClient.execute(alipaySystemOauthTokenRequest);
            AlipayUserInfoShareRequest requestUser = new AlipayUserInfoShareRequest();
            AlipayUserInfoShareResponse alipayUserInfoShareResponse = alipayClient.execute(requestUser,
                    alipaySystemOauthTokenResponse.getAccessToken());
            logger.info("auth_code:{},srcUrl:{}", auth_code, srcUrl);
            if (alipayUserInfoShareResponse.isSuccess()) {
                logger.info("openId:{}", alipayUserInfoShareResponse.getUserId());
                String decodeSrcUrl = new String(Base64Utils.decodeFromString(srcUrl));
                logger.info("decodeSrcUrl:{}", decodeSrcUrl);
                log.info("userinfoAlipay:{}", JsonUtils.toJson(alipayUserInfoShareResponse));
                Map<String, String> map = Maps.newConcurrentMap();
                map.put("openId", alipayUserInfoShareResponse.getUserId());
                map.put("avatar", alipayUserInfoShareResponse.getAvatar());
                map.put("nickName", URLEncoder.encode(alipayUserInfoShareResponse.getUserName(), "UTF-8"));
                response.sendRedirect(UrlUtils.appendParams(decodeSrcUrl, map));
            }else{
                log.info("userinfoAlipay:{}", JsonUtils.toJson(alipayUserInfoShareResponse));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
